ScreenBuffer = { 
    high = 0,
    width = 0,
    bgColor = 'f',
    fgColor = '0',

    cursorX = 1,
    cursorY = 1,

    buffer = {},
    bufferDirty = {}

}

function ScreenBuffer:new(width, high)
    local obj = {}
    setmetatable(obj,self)
	self.__index = self

    obj:resize(width, high)

	return obj
end

function ScreenBuffer:resize(width, high, clear)
    self.high = high
    self.width = width

    self.bufferDirty = {}

    for i = 1, high, 1 do
        if self.buffer[i] == nil or clear then
            self.buffer[i] = {
                c = string.rep(' ', width),
                f = string.rep(self.fgColor, width), 
                b = string.rep(self.bgColor, width)
            }
        else
            self.buffer[i].c = string.sub(self.buffer[i].c..string.rep(' ', width), 1, width)
            self.buffer[i].f = string.sub(self.buffer[i].f..string.rep(' ', width), 1, width)
            self.buffer[i].b = string.sub(self.buffer[i].b..string.rep(' ', width), 1, width)
        end
        table.insert(self.bufferDirty, i)
    end
end

function ScreenBuffer:clear()
    self.buffer = {}
    self.bufferDirty = {}

    for i = 1, self.high, 1 do
        self.buffer[i] = {
            c = string.rep(' ', self.width), 
            f = string.rep(self.fgColor, self.width), 
            b = string.rep(self.bgColor, self.width)
        }
    end
end

function ScreenBuffer._toBlit(col, w)
    local t = type(col)
    if t == "number" then
        return string.rep(colors.toBlit(col), w)
    elseif t == "string" then
        if string.len(col) ~= w then
            return string.rep(colors.toBlit(string.sub(col, 1, 1)), w)
        end
    end
    return col
end

function ScreenBuffer:fill(char, x, y, width, high, fg, bg)
    local c = string.rep(char, width)
    for i = y, y+high-1, 1 do
        self:blit(c, x, i, fg, bg)
    end
end

function ScreenBuffer:blit(text, x, y, fg, bg)
    if y > self.high or x > self.width or y < 1 or x < 1 then return end
    local strL = string.len(text)
    local fg = self._toBlit(fg, strL) or string.rep(self.fgColor, strL)
    local bg = self._toBlit(bg, strL) or string.rep(self.bgColor, strL)
    local c = self.buffer[y].c
    local f = self.buffer[y].f
    local b = self.buffer[y].b
    local w = self.width
    self.buffer[y].c = string.sub(string.sub(c,1,x-1)..text..string.sub(c, x+strL, w), 1, w)
    self.buffer[y].f = string.sub(string.sub(f,1,x-1)..fg..string.sub(f, x+strL, w), 1, w)
    self.buffer[y].b = string.sub(string.sub(b,1,x-1)..bg..string.sub(b, x+strL, w), 1, w)
    self.bufferDirty[y] = true
end

function ScreenBuffer:setFgColor(color)
    self.fgColor = self._toBlit(color, 1)
end

function ScreenBuffer:setBgColor(color)
    self.bgColor = self._toBlit(color, 1)
end

function ScreenBuffer:write(text)
    local x = self.cursorX
    self:blit(text, x, self.cursorY)
    self.cursorX = x + string.len(text)
end

function ScreenBuffer:drawToScreen(screen, full)
    if (full or false) then
        for i = 1, self.high, 1 do
            screen.setCursorPos(1, i)
            screen.blit(self.buffer[i].c, self.buffer[i].f, self.buffer[i].b)
        end
    else
        for k,_ in pairs(self.bufferDirty) do
            screen.setCursorPos(1, k)
            screen.blit(self.buffer[k].c, self.buffer[k].f, self.buffer[k].b)
        end
    end
end

return ScreenBuffer